#include <vcl.h>
#pragma hdrstop

#include "GLSkel3D.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TGLForm3D *GLForm3D;
//---------------------------------------------------------------------------
__fastcall TGLForm3D::TGLForm3D(TComponent* Owner): TForm(Owner)
{
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
void __fastcall TGLForm3D::FormCreate(TObject *Sender)
{
  hdc=GetDC(Handle);
  SetPixelFormatDescriptor();
  hrc=wglCreateContext(hdc);
  if(hrc==NULL) ShowMessage("Error CreateContex");
  if(wglMakeCurrent(hdc, hrc)==false) ShowMessage("Error MakeCurrent");

  glClearColor(0.6,0.7,0.8,1.0);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);

  //Luz0
  glEnable(GL_LIGHT0);
  GLfloat LuzDifusa[]={1.0,1.0,1.0,1.0};
  glLightfv(GL_LIGHT0,GL_DIFFUSE,LuzDifusa);
  GLfloat LuzAmbiente[]={0.3,0.3,0.3,1.0};
  glLightfv(GL_LIGHT0,GL_AMBIENT,LuzAmbiente);
  PosicionLuz0[0]=25.0; PosicionLuz0[1]=25.0;
  PosicionLuz0[2]=0.0; PosicionLuz0[3]=1.0;
  glLightfv(GL_LIGHT0, GL_POSITION, PosicionLuz0);

  glEnable(GL_COLOR_MATERIAL);
  glMaterialf(GL_FRONT, GL_SHININESS, 0.1);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  glShadeModel(GL_SMOOTH);   //Defecto

  //crearObjetosEscena();
  mouseX=0;
  mouseY=0;

  eyeX=20.0,
  eyeY=200.0,
  eyeZ=20.0,
  lookX=0.0,
  lookY=0.0,
  lookZ=0.0,
  upX=0;
  upY=1;
  upZ=0;
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(eyeX,eyeY,eyeZ, lookX,lookY,lookZ, upX,upY,upZ);

  //Volumen de vista
  N=1; F=220;
  xRight=2; xLeft=-xRight;
  yTop=1; yBot=-yTop;
  //Ratio del volumen de vista =1
  //ClientWidth=400;
  //ClientHeight=400;
  RatioViewPort=1.0;

  drawWire = true;

}

//---------------------------------------------------------------------------
void __fastcall TGLForm3D::SetPixelFormatDescriptor()
{
  PIXELFORMATDESCRIPTOR pfd = {
    	sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,
        24,
        0,0,0,0,0,0,
        0,0,
        0,0,0,0,0,
        32,
        0,
        0,
        PFD_MAIN_PLANE,
        0,
        0,0,0 };
  int PixelFormat=ChoosePixelFormat(hdc,&pfd);
  SetPixelFormat(hdc,PixelFormat,&pfd);
}
//---------------------------------------------------------------------------
void __fastcall TGLForm3D::FormResize(TObject *Sender)
{
  //Se actualiza puerto de vista y ratio
  if ((ClientHeight<=1.0) || (ClientHeight<=1.0)) {
        ClientWidth=400;
        ClientHeight=400;
        RatioViewPort=1.0;
  }
  else RatioViewPort=(GLfloat)ClientWidth/(GLfloat)ClientHeight;

  glViewport(0,0,ClientWidth,ClientHeight);

  //Se actualiza el volumen de vista
  //para que su ratio coincida con RatioViewPort
  GLfloat RatioVolVista=xRight/yTop;

  if (RatioVolVista>=RatioViewPort) {
     //Aumentamos yTop-yBot
     yTop= xRight/RatioViewPort;
     yBot=-yTop;
     }
  else {
     //Aumentamos xRight-xLeft
     xRight=RatioViewPort*yTop;
     xLeft=-xRight;
     }

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(xLeft,xRight, yBot,yTop, N,F);

  GLScene();
}
//---------------------------------------------------------------------------
void __fastcall TGLForm3D::GLScene()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLightfv(GL_LIGHT0,GL_POSITION,PosicionLuz0);

  glColor3f(0.0,0.0,0.0);
  glBegin(GL_LINES);

    glVertex3f(0.0,0.0,0.0);
    glVertex3f(0.0,0.0,3.0);
    glVertex3f(0.0,0.0,0.0);
    glVertex3f(0.0,3.0,0.0);
    glVertex3f(0.0,0.0,0.0);
    glVertex3f(3.0,0.0,0.0);
  glEnd();
  // Dibujar la escena
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glScaled(0.2,0.2,0.2);
  glColor3f(1.0,1.0,0.0);
  if (spiral!=NULL)
        spiral->draw(drawWire);

 glMatrixMode(GL_MODELVIEW);
  glPushMatrix();

        // Posicion de la pelota en la espiral
        VectorPoint3D* p=localCoordinates(t);
        float x = cos(t)+t*sin(t);
        float y = 0;
        float z = sin(t)-t*cos(t);

        glTranslated(x,y,z);
        glRotated(angle2,1,0,0);
        glRotated(angle,0,0,1);
        delete p;

        if (glass!=NULL) {
                glass->draw(drawWire);
        }

        if (ball!=NULL)
                ball->dibuja();
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glTranslated(3,0,0);
        glScaled(0.4,0.4,0.4);
        glRotated(90,0,0,1);
        glColor3f(0.1,0.1,0.1);

        glPopMatrix();
        glPopMatrix();
        glPopMatrix();
        //glFlush();
        SwapBuffers(hdc);
}
//---------------------------------------------------------------------------
void __fastcall TGLForm3D::FormPaint(TObject *Sender)
{
  GLScene();
}
//---------------------------------------------------------------------------
void __fastcall TGLForm3D::FormDestroy(TObject *Sender)
{
  liberarObjetosEscena();
  ReleaseDC(Handle,hdc);
  wglMakeCurrent(NULL,NULL);
  wglDeleteContext(hrc);
}
//---------------------------------------------------------------------------
void TGLForm3D::crearObjetosEscena()
{
}
//---------------------------------------------------------------------------
void TGLForm3D::liberarObjetosEscena()
{
/*        if (ball!=NULL)
                delete ball;
*/
}


//---------------------------------------------------------------------------
 VectorPoint3D* TGLForm3D::localCoordinates(float t){
        float x = cos(t)+t*sin(t);
        float y = 0;
        float z = sin(t)-t*cos(t);
        VectorPoint3D* ec = new VectorPoint3D(x,y,z);
        float x1 =- sin(t)+(sin(t)+(t*cos(t)));
        float y1 = 0;
        float z1 = cos(t)-cos(t)+(t*sin(t));
        VectorPoint3D* ec1 = new VectorPoint3D(x1,y1,z1);
        float x2 =- cos(t)+cos(t)+(cos(t)-(t*sin(t)));
        float y2 = 0;
        float z2 =- sin(t)+sin(t)+ sin(t)+(t*cos(t));
        VectorPoint3D* ec2 = new VectorPoint3D( x2 , y2 , z2 ) ;
        VectorPoint3D* Tt = new VectorPoint3D( ec1->getX( ) , ec1->getY( ) , ec1->getZ( ) );
        Tt->normalice( );
        VectorPoint3D* Bt = ec1->prodVectorial( ec2 );
        Bt->normalice( );
        VectorPoint3D* Nt = Bt->prodVectorial( Tt );
        Nt->normalice( );

        float M[4][4];

        M[0][0]=Nt->getX() ; M[0][1]=Bt->getX() ; M[0][2]=Tt->getX() ; M[0][3]=x;
        M[1][0]=Nt->getY() ; M[1][1]=Bt->getY() ; M[1][2]=Tt->getY() ; M[1][3]=y;
        M[2][0]=Nt->getZ() ; M[2][1]=Bt->getZ() ; M[2][2]=Tt->getZ() ; M[2][3]=z;
        M[3][0]=0.0;       M[3][1]=0.0;       M[3][2]=0.0;       M[3][3]=1.0;


        float u = M[0][3];
        float v = M[1][3];
        float w = M[2][3];

        delete ec;  delete Tt;
        delete ec1; delete Bt;
        delete ec2; delete Nt;
        return new VectorPoint3D(u,v,w);
}

void __fastcall TGLForm3D::FormKeyPress(TObject *Sender, char &Key)
{
        if (Key=='q')
                angle+=10;
        else if (Key=='w')
                angle-=10;
        else if (Key=='a')
                angle2+=10;
        else if (Key=='s')
                angle2-=10;
        else if (Key=='e')
                t+=0.1;
        else if (Key=='r' && t>0)
                t-=0.1;
        else if (Key=='t')
                drawWire = !drawWire;
        GLScene();

}
//---------------------------------------------------------------------------


void __fastcall TGLForm3D::Espiral1Click(TObject *Sender)
{
        if (glass!=NULL) {
                delete glass;
                delete mallaSup;
                delete mallaCuenco;
                glass = NULL;
                mallaSup = NULL;
                mallaCuenco = NULL;
        }

        spiral = new Spiral(50,2,100);
        ball = new Ball();
        angle = 0;
        angle2 = 90;
        t=0;
        GLScene();
}
//---------------------------------------------------------------------------

void __fastcall TGLForm3D::Copa1Click(TObject *Sender)
{
        if (ball!=NULL) {
                delete ball;
                delete spiral;
                ball = NULL;
                spiral = NULL;
        }

        /**********************
        * La llamada es como sigue:
        *   Glass(
        *     num_lados            - numero de lados del perimetro
        *     num_alturas_seccion  - numero de lados en altura de cada seccion
        *                            (copa, tallo y base)
        *     d1, d2, d3, d4       - diametros de la base, el comienzo del tallo,
        *                            el comienzo de la copa y el final de la copa
        *     a1, a2, a3, a4       - alturas de la base, el comienzo del tallo,
        *                            el comienzo de la copa y el final de la copa
        *
        *  NOTA: Centrando a3 en 0 se evita el escalon resultante del salto
        *        entre la parte lineal y la parte exponencial de la curva
        ***********************/
        glass = new Glass(40,40,
                           1.50,  0.10,  0.25,  2.00,
                          -3.75, -3.50,  0.00,  5.00);
        GLScene();
}
//---------------------------------------------------------------------------


